/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.i18n.provider;

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.runtime.msu.ServiceUnitConfigService;
import io.iec.edp.caf.commons.runtime.msu.entities.MsuCommonInfo;
import io.iec.edp.caf.i18n.spi.ResourceResolver;
import io.iec.edp.caf.i18n.utils.MyFileFilter;
import io.iec.edp.caf.i18n.utils.ResourceMetadataMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * MSU部署时的资源文件获取类
 * exception.properties
 * |
 * zh-CHT --> exception.zh-CHT.properties
 * |
 * en --> exception.en.properties
 *
 * @author manwenxing01
 */
@Slf4j
public class SuPathResourceResolver implements ResourceResolver {

    //su与su路径映射map      <su, suPath>
    private final static Map<String, String> SuPathSet = new ConcurrentHashMap<>();

    //.resmap映射文件集合     <su, <metadataId, properties>>
    private final static Map<String, HashMap<String, String>> MapperSet = new ConcurrentHashMap<>();

    //资源文件与ResourceBundle的映射map     <language--su--resource, lastModifiedTime>
    private final static Map<String, ResourceBundle> ResourceSet = new ConcurrentHashMap<>();

    //.properties文件最后修改时间集合(决定是否重新获取资源文件内容)     <language--su--resource, lastModifiedTime> + <"Mapper--" + su + "--" + name, lastModifiedTime>
    private final static Map<String, Long> FileLastModifiedTimeSet = new ConcurrentHashMap<>();

    @Override
    public ResourceBundle getResource(String pathId, String fileName, String language) {
        String su = getSu(pathId);
        String name = getResourceFileName(fileName, su);
        //先尝试获取自定义带语言的文件名
        ResourceBundle bundle = getCustomBundle(name, su, language);
        if (bundle == null) {
            //如果未取出，则按原文件名获取
            bundle = getResourceBundle(doGetFile(name, su, language), su, language);
        }

        return bundle;
    }

    /**
     * 获取自定义资源包
     */
    private ResourceBundle getCustomBundle(String fileName, String su, String language) {
        //尝试获取自定义带语言的文件名
        File file = doGetFile(getCustomFileName(fileName), su, language);
        return getResourceBundle(file, su, language);
    }

    private File doGetFile(String fileName, String su, String language) {
        String resource = getSuResourcesPath(su);
        String path = resource + File.separator + language + File.separator + String.format("%s.%s.properties", fileName, language);
        if (!new File(path).exists()) {
            path = resource + File.separator + String.format("%s.properties", fileName);
        }

        //.properties文件不存在，返回null
        File file = new File(path);
        if (!file.exists()) return null;

        return file;
    }

    //获取.properties文件名
    private String getResourceFileName(String resource, String su) {
        if (StringUtils.endsWithIgnoreCase(resource, ".properties")) {
            //resource为资源文件名
            return resource.trim().substring(0, resource.length() - 11);
        } else {
            //resource为资源元数据id
            return getFileName(resource, su);
        }
    }

    private ResourceBundle getResourceBundle(File file, String su, String language) {
        ResourceBundle bundle = null;

        if (file != null && file.exists()) {
            //log file path
            if (log.isDebugEnabled()) {
                log.debug("su = {}, language = {}, file path = {}.", su, language, file.getAbsolutePath());
            }

            //定义.properties标识（language--su--fileName）
            String dimension = String.format("%s--%s--%s", language, StringUtils.isEmpty(su) ? "caf" : su.toLowerCase(), file.getName());
            //resourceBundle不存在，第一次获取
            if (!ResourceSet.containsKey(dimension)) {
                FileLastModifiedTimeSet.put(dimension, file.lastModified());
                ResourceSet.put(dimension, extractResourceBundle(file));
            }

            //resourceBundle存在，但是文件已经更新
            if (ResourceSet.containsKey(dimension) && !FileLastModifiedTimeSet.get(dimension).equals(file.lastModified())) {
                FileLastModifiedTimeSet.put(dimension, file.lastModified());
                ResourceSet.put(dimension, extractResourceBundle(file));
            }

            bundle = ResourceSet.get(dimension);
        }

        return bundle;
    }

    /**
     * 根据文件路径从外部读取资源包
     */
    private ResourceBundle extractResourceBundle(File file) {
        ResourceBundle rb = null;
        BufferedInputStream inputStream = null;
        InputStreamReader reader = null;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(file));
            reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            rb = new PropertyResourceBundle(reader);
        } catch (IOException e) {
            log.error("Error on reading .properties [{}] !", file.getAbsolutePath(), e);
        } finally {
            try {
                reader.close();
            } catch (IOException ignored) {
            }
            try {
                inputStream.close();
            } catch (IOException ignored) {
            }
        }

        return rb;
    }

    /**
     * 根据资源元数据id、su获取元数据对应的资源文件名
     */
    private String getFileName(String metadataId, String su) {
        if (!MapperSet.containsKey(su)) {
            MapperSet.put(su, getMapperSet(su));
        }

        return MapperSet.get(su).get(metadataId);
    }

    /**
     * 读取su中.resmap文件内容
     */
    private HashMap<String, String> getMapperSet(String su) {
        HashMap<String, String> map = new HashMap<>();
        //资源文件路径下路径信息
        String resourcesPath = getSuResourcesPath(su);

        //读取资源文件路径下所有后缀为.resmap的文件信息
        File resources = new File(resourcesPath);
        String[] resmapFileNames = resources.list(new MyFileFilter("resmap"));

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        if (resmapFileNames != null) {
            for (String name : resmapFileNames) {
                File file = new File(resourcesPath + File.separator + name);

                //读取.resmap文件内容
                ResourceMetadataMapper mapper = null;
                try {
                    mapper = objectMapper.readValue(file, ResourceMetadataMapper.class);
                } catch (IOException e) {
                    //吞掉异常，记录日志
                    log.error("Error on reading .resmap [" + file.getAbsolutePath() + "] !", e);
                }
                if (mapper != null && mapper.getMetadataIds() != null) {
                    for (String id : mapper.getMetadataIds()) {
                        map.put(id, mapper.getProjectName());
                    }
                }
            }
        }

        return map;
    }

    /**
     * 获取su的resources目录路径
     */
    private String getSuResourcesPath(String su) {
        return getSuPath(su) + File.separator + "resources";
    }

    /**
     * 获取su的路径
     */
    private String getSuPath(String su) {
        if (!SuPathSet.containsKey(su)) {
            List<MsuCommonInfo> allSuInfo = ServiceUnitConfigService.getAllSuInfo();
            if (allSuInfo != null && allSuInfo.size() > 0) {
                if (SuPathSet.isEmpty()) {
                    //如果suPathSet为空，把所有su放入
                    allSuInfo.forEach(info -> SuPathSet.put(info.getName().toLowerCase(), info.getPath()));
                    //CAF的path
                    SuPathSet.put("caf", CafEnvironment.getServerRTPath() + File.separator + "platform" + File.separator + "common");
                } else {
                    //不为空，单独获取当前su
                    MsuCommonInfo serviceInfo = allSuInfo.stream().filter(info -> su.equalsIgnoreCase(info.getName())).findFirst().orElse(null);
                    if (serviceInfo != null) SuPathSet.put(su, serviceInfo.getPath());
                }
            }
        }
        if (!SuPathSet.containsKey(su) || SuPathSet.get(su) == null) {
            log.error("Can't find path for su [" + su + "] !");
        }

        return SuPathSet.getOrDefault(su, "");
    }

    /**
     * 根据文件名称获取用户扩展的资源文件
     */
    private String getCustomFileName(String fileName) {
        return String.format("%s.custom", fileName);
    }

    //获取su
    private String getSu(String su) {
        return StringUtils.isEmpty(su) ? "caf" : su.toLowerCase();
    }

}
